package com.ccp.dev.workflow.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.Dom4jUtil;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.core.util.XmlBeanUtil;
import com.ccp.dev.form.xml.util.XmlUtil;
import com.ccp.dev.system.model.SysOrg;
import com.ccp.dev.workflow.model.Identity;
import com.ccp.dev.workflow.dao.IdentityDao;
import com.ccp.dev.workflow.xml.IdentityXml;
import com.ccp.dev.workflow.xml.IdentityXmlList;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * ClassDescribe  流水号 service类
 * @author: fanruiqi
 * Date: 2019-08-29
 * Since:1
 * To change this template use File | Settings | File Templates.
 */

@Service
public class IdentityService extends BaseService<Identity> {

    @Resource
    IdentityDao identityDao;

    /**
     * 添加或更新流水号
     *
     * @param identity 流水号对象
     */
    @Transactional(rollbackFor = Exception.class)
    public int addOrUpdate(Identity identity) {
        int count;
        if (StringUtil.isEmpty(identity.getId())) {
            identity.setId(UUIDUtils.getUUIDFor32());
            //设置默认当前值和当前时间
            identity.setCurValue(Identity.BEGIN_CURVALUE);
            identity.setCurDate(IdentityService.getCurDate(identity.getGenType()));
            count = identityDao.add(identity);
        } else {
            count = identityDao.update(identity);
        }
        return count;
    }

    /**
     * 判断别名是否存在
     *
     * @param alias 流水号别名
     * @param id    流水号id
     * @return 是否存在此别名
     */
    public boolean isAliasExisted(String alias, String id) {
        int count = identityDao.isAliasExisted(alias, id);
        return count > 0;
    }

    /**
     * 根据alias查询流水号生成明细
     * @param alias
     * @return
     */
    public Identity getByAlias(String alias) {
        return identityDao.getByAlias(alias);
    }

    /**
     * 判断流水号别名和Alias的字节长度是否超过Oracle中的字节 name小于50 alias小于20
     * @param alias
     * @param identityName
     * @return
     */
    public String nameAndAlias(String alias, String identityName) {
        if(StringUtil.isNotEmpty(identityName) && StringUtil.isNotEmpty(alias)){
            if(identityName.getBytes().length>50){
                return "identity.save.name.failure";
            }
            if(alias.getBytes().length>20){
                return "identity.save.alias.failure";
            }
        }
        return null;
    }

    /**
     * 根据名称查询流水号明细
     * @param identityName 流水号名称
     * @return 流水号对象
     */
    public Identity getByIdentityName(String identityName) {
        return identityDao.getByIdentityName(identityName);
    }

    class Result {
        private int result = 0;
        private String no = "";

        public int getResult() {
            return result;
        }

        public void setResult(int result) {
            this.result = result;
        }

        public String getNo() {
            return no;
        }

        public void setNo(String no) {
            this.no = no;
        }
    }

    /**
     * 根据流程规则别名获取得下一个流水号
     *
     * @param alias 流水号规则别名
     * @return 下一个流水号
     */
    public String nextId(String alias) {
        IdentityService.Result result = getResult(alias);
        int i = 0;
        while (result.getResult() == 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            i++;
            result = getResult(alias);
        }
        return result.getNo();
    }

    /**
     * 获取Result对象
     * @param alias 流水号规则别名
     * @return Result对象
     */
    private IdentityService.Result getResult(String alias) {
        Identity identity = identityDao.getByAlias(alias);
        String rule = identity.getRule();
        int step = identity.getStep();
        short genType = identity.getGenType();
        Long curValue = identity.getCurValue();
        if (curValue == -1L) {
            curValue = new Long(identity.getInitValue());
        }
        //每天每月每年生成
        if (genType > 0) {
            String curDate = getCurDate(genType);
            String oldDate = identity.getCurDate();
            if (!oldDate.startsWith(curDate)) {
                identity.setCurDate(curDate);
                curValue = new Long(identity.getInitValue());
            } else {
                curValue = curValue + step;
            }
        } else {
            curValue = curValue + step;
        }
        identity.setNewCurValue(curValue);
        int i = identityDao.updateVersion(identity);
        IdentityService.Result result = new IdentityService.Result();
        if (i > 0) {
            String rtn = getByRule(rule, identity.getNoLength(), curValue, identity.getUserCode());
            result = new IdentityService.Result();
            result.setResult(1);
            result.setNo(rtn);
        }
        return result;
    }

    /**
     * 返回当前日期,格式为年月日
     * @param genType 生成类型 1:每天生成 2:每月生成 3:每年生成 0:递增
     * @return 当前日期
     */
    public static String getCurDate(short genType) {
        String str;
        Calendar calendar = Calendar.getInstance();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        int monthVal = calendar.get(Calendar.MONTH);
        int dayVal = calendar.get(Calendar.DAY_OF_MONTH);
        String month = monthVal < 10 ? "0" + (monthVal + 1) : (monthVal + 1) + "";
        String day = dayVal < 10 ? "0" + dayVal : dayVal + "";
        switch (genType) {
            case 1:
                str = year + "" + month + "" + day;
                break;
            case 2:
                str = year + "" + month;
                break;
            case 3:
                str = year;
                break;
            default:
                str = "";
                break;
        }
        return str;
    }

    /**
     * 根据规则返回需要显示的流水号
     *
     * @param rule     流水号规则
     * @param length   流水号的长度
     * @param curValue 流水号的当前值
     * @return 需要显示的流水号
     */
    private String getByRule(String rule, int length, Long curValue, String userCode) {
        Calendar calendar = Calendar.getInstance();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        String shortMonth = "" + month;
        String longMonth = (month < 10) ? "0" + month : "" + month;
        String seqNo = getSeqNo(rule, curValue, length);
        String shortDay = "" + day;
        String longDay = (day < 10) ? "0" + day : "" + day;
        String rtn = rule.replace("{yyyy}", year)
                .replace("{MM}", longMonth)
                .replace("{mm}", shortMonth)
                .replace("{DD}", longDay)
                .replace("{dd}", shortDay)
                .replace("{NO}", seqNo)
                .replace("{no}", seqNo);

        SysOrg sysOrg = (SysOrg) ContextUtil.getCurrentOrg();
        if (sysOrg != null && sysOrg.getCode() != null) {
            rtn = rtn.replace("{ORG}", sysOrg.getCode());
        } else {
            rtn = rtn.replace("{ORG}", "");
        }
        rtn = rtn.replace("{uc}", userCode == null ? "" : userCode).replace("{UC}", userCode == null ? "" : userCode);
        return rtn;
    }

    /**
     * 根据当前流水号的值和流水号显示的长度
     * <pre>
     * 比如：当前流水号为55 ，显示长度为5那么这个方法返回：00055
     * </pre>
     * @param rule     流水号规则
     * @param curValue 当前流水号的值
     * @param length   显示的长度
     *
     * @return 字符串
     */
    private static String getSeqNo(String rule, Long curValue, int length) {
        String tmp = curValue + "";
        int len;
        if (rule.indexOf("no") > -1) {
            len = length;
        } else {
            len = length - tmp.length();
        }
        String rtn = "";
        switch (len) {
            case 1:
                rtn = "0";
                break;
            case 2:
                rtn = "00";
                break;
            case 3:
                rtn = "000";
                break;
            case 4:
                rtn = "0000";
                break;
            case 5:
                rtn = "00000";
                break;
            case 6:
                rtn = "000000";
                break;
            case 7:
                rtn = "0000000";
                break;
            case 8:
                rtn = "00000000";
                break;
            case 9:
                rtn = "000000000";
                break;
            case 10:
                rtn = "0000000000";
                break;
            case 11:
                rtn = "00000000000";
                break;
            case 12:
                rtn = "000000000000";
                break;
            default:
                rtn = "";
                break;
        }
        if (rule.indexOf("no") > -1) {
            return tmp + rtn;
        } else {
            return rtn + tmp;
        }

    }

    /**
     * 获取所有流水号
     * @return
     */
    public List<Identity> queryAll() {
        return identityDao.queryAll();
    }

    /**
     * 导入XML
     * @param inputStream
     * @return 是否成功导入 true,成功;false,失败
     * @throws Exception
     */
    public void importXml(InputStream inputStream) throws Exception {
        Document doc = Dom4jUtil.loadXml(inputStream);
        Element root = doc.getRootElement();
        //验证格式
        XmlUtil.checkXmlFormat(root, "system", "identities");

        String xmlStr = root.asXML();
        IdentityXmlList identityXmlList = (IdentityXmlList) XmlBeanUtil.unmarshall(xmlStr,IdentityXmlList.class);

        List<IdentityXml> list = identityXmlList.getIdentityXmlList();

        //判断导入信息是否已存在
        for (IdentityXml identityXml : list) {
            // 导入表，并解析相关信息
            this.importIdentityXml(identityXml);
        }
    }

    /**
     * 导入数据库，并解析
     * @param identityXml 流水号XML
     * @return 是否成功导入 true,成功;false,失败
     * @throws Exception
     */
    private void importIdentityXml(IdentityXml identityXml) throws Exception {
        Identity identity = identityXml.getIdentity();
        if (BeanUtils.isEmpty(identity)) {
            throw new Exception();
        }
        String alias = identity.getAlias();
        String id = identity.getId();
        //只判断别名是否存在
        if (this.isAliasExisted(alias,null)) {
            throw new RuntimeException("别名为‘" + alias + "’的流水号已经存在，请检查你的xml文件！");
        }else{
            identity.setId(UUIDUtils.getUUIDFor32());
            identityDao.add(identity);
        }
    }

    /**
     * 导出全部流水号
     * @param identities
     * @return
     * @throws Exception
     */
    public String exportXml(List<Identity> identities) throws Exception {
        IdentityXmlList identityXmlList = new IdentityXmlList();
        List<IdentityXml> list = new ArrayList<IdentityXml>();
        for (Identity identity:identities) {
            IdentityXml identityXml =this.exportIdentityXml(identity);
            list.add(identityXml);
        }
        identityXmlList.setIdentityXmlList(list);
        return XmlBeanUtil.marshall(identityXmlList, IdentityXmlList.class);
    }

    /**
     * 导出流水号XML
     * @param tableIds
     * @return
     * @throws Exception
     */
    public String exportXml(String[] tableIds) throws Exception {
        IdentityXmlList identityXmlList = new IdentityXmlList();
        List<IdentityXml> list = new ArrayList<IdentityXml>();
        for (int i = 0; i < tableIds.length; i++) {
            Identity identity = identityDao.getById(tableIds[i]);
            IdentityXml identityXml =this.exportIdentityXml(identity);
            list.add(identityXml);
        }
        identityXmlList.setIdentityXmlList(list);
        return XmlBeanUtil.marshall(identityXmlList, IdentityXmlList.class);
    }

    /**
     * 导出表的信息
     * @param identity
     * @return
     */
    private IdentityXml exportIdentityXml(Identity identity) {
        IdentityXml identityXml=new IdentityXml();
        String id   =   identity.getId();
        if(BeanUtils.isNotIncZeroEmpty(id) ){
            //导出流水号
            identityXml.setIdentity(identity);
        }
        return identityXml;
    }

}
